package edu.se.jai.gameservice.service;

import edu.se.jai.gameservice.entity.GameRoom;
import edu.se.jai.gameservice.entity.Player;
import edu.se.jai.openfeignapi.dto.GameStatus;
import edu.se.jai.openfeignapi.dto.GuessResultDto;
import edu.se.jai.openfeignapi.dto.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 游戏服务类（多实例版本 - 使用Redis共享缓存）
 * 
 * 🎯 核心功能：
 * - 支持多实例部署，解决单实例版本的缓存一致性问题
 * - 使用Redis作为共享缓存，确保数据在实例间同步
 * - 优化Redis数据结构，避免性能瓶颈
 * - 自动缓存管理，确保数据一致性
 * 
 * 📊 Redis Key 设计：
 * - room:{roomId} -> GameRoom对象 (JSON序列化，手动清理)
 * - player:{sessionId} -> Player对象 (JSON序列化，手动清理)
 * - player_room:{sessionId} -> 房间ID字符串 (手动清理)
 * - player_names -> Set<String> 玩家名称集合 (去重，O(1)查询，手动清理)
 * - rooms_by_time -> ZSet<String, Long> 房间时间排序集合 (按创建时间排序，手动清理)
 * 
 * 🚀 性能优化：
 * - 使用Set进行玩家名称去重，避免KEYS命令
 * - 使用ZSet进行房间时间排序，支持高效分页
 * - 双RedisTemplate设计：自定义对象存储 + Spring Boot自动配置的字符串/集合操作
 * - 启动时自动清理缓存，确保干净状态
 * 
 * 🔧 缓存管理：
 * - 启动时自动清除所有缓存 (@EventListener ApplicationReadyEvent)
 * - 断线时智能清理玩家信息 (WebSocketEventListener)
 * - 异常情况下也会尝试清理，避免僵尸数据
 * 
 * ⚠️ 注意：使用内部实体（Player, GameRoom），包含敏感信息如 targetNumber
 */
@Slf4j
@Service
public class GameService {

    /** 每个房间最大玩家数 */
    @Value("${game.max-players-per-room:8}")
    private int maxPlayersPerRoom;

    // ==================== Redis模板注入 ====================
    
    /** 自定义RedisTemplate - 用于存储复杂对象（GameRoom, Player等），使用JSON序列化 */
    @Autowired
    private RedisTemplate<String, Object> objectRedisTemplate;

    /** Spring Boot自动配置的StringRedisTemplate - 用于字符串和集合操作（Set, ZSet等） */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    // ==================== Redis Key 常量定义 ====================
    
    /** 房间信息Key前缀 - 存储GameRoom对象 */
    private static final String ROOM_KEY_PREFIX = "room:";
    
    /** 玩家信息Key前缀 - 存储Player对象 */
    private static final String PLAYER_KEY_PREFIX = "player:";
    
    /** 玩家房间映射Key前缀 - 存储房间ID字符串 */
    private static final String PLAYER_ROOM_KEY_PREFIX = "player_room:";
    
    /** 玩家名称集合Key - Set<String>，用于去重检查，O(1)时间复杂度 */
    private static final String PLAYER_NAMES_SET_KEY = "player_names";
    
    /** 房间时间排序集合Key - ZSet<String, Long>，按创建时间排序，支持高效分页 */
    private static final String ROOMS_ZSET_KEY = "rooms_by_time";

    // ==================== 启动时初始化方法 ====================

    /**
     * 🚀 应用启动完成后清除所有Redis缓存
     * 
     * 功能说明：
     * - 确保每次启动都是干净的状态，避免历史数据干扰
     * - 清除所有游戏相关的Redis数据：房间、玩家、映射关系等
     * - 使用ApplicationReadyEvent确保所有Bean都已初始化完成
     * 
     * 执行时机：Spring Boot应用完全启动后
     * 异常处理：即使清除失败也不会影响服务启动
     */
    @EventListener(ApplicationReadyEvent.class)
    public void onApplicationReady() {
        log.info("🚀 Game Service 启动完成，开始清除Redis缓存...");
        try {
            Result<String> result = clearAllCache();
            if (result.isSuccess()) {
                log.info("✅ Redis缓存清除成功: {}", result.getData());
            } else {
                log.error("❌ Redis缓存清除失败: {}", result.getErrorMessage());
            }
        } catch (Exception e) {
            log.error("❌ 启动时清除Redis缓存发生异常: {}", e.getMessage(), e);
        }
        log.info("🎮 Game Service 初始化完成，准备接收请求");
    }

    // ==================== 玩家管理方法 ====================
    
    /**
     * 👤 注册玩家会话
     * 
     * 功能说明：
     * - 检查玩家名称是否重复（使用Redis Set，O(1)时间复杂度）
     * - 创建玩家对象并存储到Redis
     * - 将玩家名称添加到全局Set中，用于去重检查
     * 
     * 性能优化：
     * - 使用Set.isMember()替代KEYS命令，避免阻塞操作
     * - 支持高并发玩家注册
     * 
     * @param sessionId 会话ID（WebSocket连接标识）
     * @param playerName 玩家名称（全局唯一）
     * @return 注册结果，成功返回玩家名称
     */
    public Result<String> registerPlayerSession(String sessionId, String playerName) {
        // 🔍 检查玩家名是否重复 - 使用Set，O(1)时间复杂度，避免KEYS命令
        if (stringRedisTemplate.opsForSet().isMember(PLAYER_NAMES_SET_KEY, playerName)) {
            return Result.failure("玩家名称已存在，请选择其他名称");
        }

        // 👤 创建玩家并注册会话
        Player player = createPlayer(playerName, sessionId);
        String playerKey = PLAYER_KEY_PREFIX + sessionId;
        objectRedisTemplate.opsForValue().set(playerKey, player);
        
        // 📝 将玩家名添加到Set中，用于后续去重检查
        stringRedisTemplate.opsForSet().add(PLAYER_NAMES_SET_KEY, playerName);

        log.info("玩家 {} 会话注册成功，Session ID: {}", playerName, sessionId);
        return Result.success(playerName);
    }

    /**
     * 根据会话ID获取玩家信息
     * 
     * @param sessionId 会话ID
     * @return 玩家对象，如果不存在则返回null
     */
    public Player getPlayerBySessionId(String sessionId) {
        String playerKey = PLAYER_KEY_PREFIX + sessionId;
        return (Player) objectRedisTemplate.opsForValue().get(playerKey);
    }
    
    /**
     * 🧹 清除玩家会话信息（断开连接时调用）
     * 
     * 功能说明：
     * - 删除玩家的基本信息（Player对象）
     * - 从玩家名称Set中移除该玩家
     * - 删除玩家房间映射关系
     * - 用于断线时清理玩家数据，避免僵尸数据
     * 
     * 使用场景：
     * - WebSocket断线时自动调用
     * - 玩家主动退出时调用
     * - 异常情况下的数据清理
     * 
     * @param sessionId 会话ID（WebSocket连接标识）
     * @return 清除结果，成功返回清理信息
     */
    public Result<String> clearPlayerSession(String sessionId) {
        try {
            // 1. 获取玩家信息
            Player player = getPlayerBySessionId(sessionId);
            if (player == null) {
                log.info("玩家信息不存在，无需清除 - Session ID: {}", sessionId);
                return Result.success("玩家信息不存在");
            }
            
            String playerName = player.getName();
            
            // 2. 清除玩家基本信息
            String playerKey = PLAYER_KEY_PREFIX + sessionId;
            objectRedisTemplate.delete(playerKey);
            
            // 3. 从玩家名Set中移除
            stringRedisTemplate.opsForSet().remove(PLAYER_NAMES_SET_KEY, playerName);
            
            // 4. 清除玩家房间映射
            String playerRoomKey = PLAYER_ROOM_KEY_PREFIX + sessionId;
            stringRedisTemplate.delete(playerRoomKey);
            
            log.info("已清除玩家信息 - Session ID: {}, 玩家名: {}", sessionId, playerName);
            return Result.success("玩家信息已清除");
            
        } catch (Exception e) {
            log.error("清除玩家信息时发生异常 - Session ID: {}, 异常: {}", sessionId, e.getMessage(), e);
            return Result.failure("清除玩家信息失败: " + e.getMessage());
        }
    }

    // ==================== 房间管理方法 ====================
    
    /**
     * 🏠 创建新房间
     * 
     * 功能说明：
     * - 检查玩家是否已在其他房间中
     * - 创建新的游戏房间并存储到Redis
     * - 建立玩家与房间的映射关系
     * - 将房间ID添加到时间排序集合中
     * 
     * Redis操作：
     * - 存储房间对象：room:{roomId} -> GameRoom
     * - 存储玩家房间映射：player_room:{sessionId} -> roomId
     * - 添加到时间排序集合：rooms_by_time -> ZSet(roomId, timestamp)
     * 
     * @param sessionId 创建者的会话ID（WebSocket连接标识）
     * @return 创建结果，成功返回房间信息
     */
    public Result<GameRoom> createRoom(String sessionId) {
        // 检查玩家是否已经加入了其他房间
        String playerRoomKey = PLAYER_ROOM_KEY_PREFIX + sessionId;
        if (stringRedisTemplate.hasKey(playerRoomKey)) {
            return Result.failure("您已经加入了其他房间，不能创建新房间");
        }

        // 创建房间对象
        String roomId = generateRoomId();
        GameRoom room = new GameRoom();
        room.setRoomId(roomId);
        room.setCreatorSessionId(sessionId);
        room.setStatus(GameStatus.WAITING);
        room.setTargetNumber(generateTargetNumber());

        // 创建者自动加入房间
        Player creator = getPlayerBySessionId(sessionId);
        if (creator == null) {
            return Result.failure("玩家信息不存在");
        }
        
        room.getPlayers().put(sessionId, creator);
        room.setCreatorName(creator.getName());
        
        // 保存到Redis
        String roomKey = ROOM_KEY_PREFIX + roomId;
        objectRedisTemplate.opsForValue().set(roomKey, room);
        stringRedisTemplate.opsForValue().set(playerRoomKey, roomId);
        
        // 使用ZSet存储房间，分数为当前时间戳（最新的房间分数最高）
        long timestamp = System.currentTimeMillis();
        stringRedisTemplate.opsForZSet().add(ROOMS_ZSET_KEY, roomId, timestamp);

        log.info("创建新房间: {}，创建者: {}", roomId, creator.getName());
        return Result.success(room);
    }

    /**
     * 加入房间
     * 
     * @param sessionId 玩家会话ID
     * @param roomId 房间ID
     * @return 加入结果
     */
    public Result<GameRoom> joinRoom(String sessionId, String roomId) {
        // 检查玩家是否已经加入了其他房间
        String playerRoomKey = PLAYER_ROOM_KEY_PREFIX + sessionId;
        if (stringRedisTemplate.hasKey(playerRoomKey)) {
            return Result.failure("您已经加入了其他房间，不能加入更多房间");
        }
        
        // 获取房间信息
        String roomKey = ROOM_KEY_PREFIX + roomId;
        GameRoom room = (GameRoom) objectRedisTemplate.opsForValue().get(roomKey);
        if (room == null) {
            return Result.failure("房间不存在");
        }

        // 获取玩家信息
        Player player = getPlayerBySessionId(sessionId);
        if (player == null) {
            return Result.failure("玩家信息不存在");
        }

        // 检查房间是否已满
        if (room.getPlayers().size() >= maxPlayersPerRoom) {
            return Result.failure("房间已满");
        }
        
        // 检查房间状态，只有WAITING状态才能加入
        if (room.getStatus() != GameStatus.WAITING) {
            return Result.failure("游戏已开始，无法加入");
        }

        // 将玩家加入房间
        room.getPlayers().put(sessionId, player);
        objectRedisTemplate.opsForValue().set(roomKey, room);
        stringRedisTemplate.opsForValue().set(playerRoomKey,roomId);

        log.info("玩家 {} 加入房间 {}", player.getName(), roomId);
        return Result.success(room);
    }

    /**
     * 离开房间
     * 
     * @param sessionId 玩家会话ID
     * @param roomId 房间ID
     * @return 离开结果
     */
    public Result<GameRoom> leaveRoom(String sessionId, String roomId) {
        // 1. 根据roomId获取房间对象
        String roomKey = ROOM_KEY_PREFIX + roomId;
        GameRoom room = (GameRoom) objectRedisTemplate.opsForValue().get(roomKey);
        if (room == null) {
            return Result.failure("房间不存在");
        }

        // 2. 验证玩家是否为房间创建者
        if (room.getCreatorSessionId().equals(sessionId)) {
            return Result.failure("房间创建者不能离开房间");
        }

        // 3.从房间中移除玩家
        Player player = room.getPlayers().remove(sessionId);

        // 4. 清理玩家的player_room映射
        String playerRoomKey = PLAYER_ROOM_KEY_PREFIX + sessionId;
        stringRedisTemplate.delete(playerRoomKey);
        
        // 5. 更新房间信息到Redis
        objectRedisTemplate.opsForValue().set(roomKey, room);

        log.info("玩家 {} 离开房间 {}", player.getName(), roomId);

        return Result.success(room);
    }

    /**
     * 解散房间
     * 
     * @param sessionId 解散者的会话ID
     * @param roomId 房间ID
     * @return 解散结果
     */
    public Result<GameRoom> dissolveRoom(String sessionId, String roomId) {
        // 1. 根据roomId获取房间对象
        String roomKey = ROOM_KEY_PREFIX + roomId;
        GameRoom room = (GameRoom) objectRedisTemplate.opsForValue().get(roomKey);
        if (room == null) {
            return Result.failure("房间不存在");
        }

        // 2. 验证玩家是否为房间创建者
        if (!room.getCreatorSessionId().equals(sessionId)) {
            return Result.failure("只有房间创建者才能解散房间");
        }

        // 3. 清理所有房间内玩家的player_room映射
        for (String playerSessionId : room.getPlayers().keySet()) {
            String playerRoomKey = PLAYER_ROOM_KEY_PREFIX + playerSessionId;
            stringRedisTemplate.delete(playerRoomKey);
        }

        // 4. 从Redis中移除房间
        objectRedisTemplate.delete(roomKey);
        stringRedisTemplate.opsForZSet().remove(ROOMS_ZSET_KEY, roomId);

        log.info("房间 {} 已被创建者解散，移除了 {} 个玩家的房间映射", roomId, room.getPlayers().size());

        return Result.success(room);
    }

    /**
     * 📋 获取所有房间列表（按创建时间倒序，最新在前）
     * 
     * 功能说明：
     * - 使用Redis ZSet按时间排序获取房间列表
     * - 避免使用KEYS命令，提高查询性能
     * - 支持高并发访问
     * 
     * 性能优化：
     * - 使用ZSet.reverseRange()替代KEYS命令
     * - O(log N + M)时间复杂度，M为返回数量
     * - 支持大量房间数据的高效查询
     * 
     * @return 所有房间列表，按创建时间倒序排列
     */
    public List<GameRoom> getAllRooms() {
        return getRoomsByPage(0, -1); // -1表示获取所有
    }
    
    /**
     * 📄 分页获取房间列表（按创建时间倒序）
     * 
     * 功能说明：
     * - 使用Redis ZSet进行高效分页查询
     * - 按房间创建时间倒序排列（最新的在前）
     * - 支持大量房间数据的分页展示
     * 
     * Redis操作：
     * - 使用ZSet.reverseRange()获取排序后的房间ID
     * - 根据房间ID批量获取房间详情
     * - 避免全量数据加载，提高性能
     * 
     * @param offset 偏移量（从第几个房间开始）
     * @param limit 限制数量（-1表示获取所有）
     * @return 房间列表，按创建时间倒序排列
     */
    public List<GameRoom> getRoomsByPage(long offset, long limit) {
        // 使用ZSet获取房间ID，按分数倒序（最新的在前）
        Set<String> roomIds;
        if (limit == -1) {
            // 获取所有房间
            roomIds = stringRedisTemplate.opsForZSet().reverseRange(ROOMS_ZSET_KEY, offset, -1);
        } else {
            // 分页获取
            roomIds = stringRedisTemplate.opsForZSet().reverseRange(ROOMS_ZSET_KEY, offset, offset + limit - 1);
        }
        
        if (roomIds == null || roomIds.isEmpty()) {
            return new ArrayList<>();
        }
        
        List<GameRoom> rooms = new ArrayList<>();
        for (String roomId : roomIds) {
            String roomKey = ROOM_KEY_PREFIX + roomId;
            GameRoom room = (GameRoom) objectRedisTemplate.opsForValue().get(roomKey);
            if (room != null) {
                rooms.add(room);
            }
        }
        return rooms;
    }
    
    /**
     * 获取最新的N个房间
     * 
     * @param count 房间数量
     * @return 最新的房间列表
     */
    public List<GameRoom> getLatestRooms(int count) {
        return getRoomsByPage(0, count);
    }

    /**
     * 根据会话ID获取所在房间
     * 
     * @param sessionId 会话ID
     * @return 房间对象，如果不存在则返回null
     */
    public GameRoom getRoomBySessionId(String sessionId) {
        String playerRoomKey = PLAYER_ROOM_KEY_PREFIX + sessionId;
        String roomId = stringRedisTemplate.opsForValue().get(playerRoomKey);
        if (roomId != null) {
            String roomKey = ROOM_KEY_PREFIX + roomId;
            return (GameRoom) objectRedisTemplate.opsForValue().get(roomKey);
        }
        return null;
    }

    /**
     * 根据房间ID获取房间
     * 
     * @param roomId 房间ID
     * @return 房间对象，如果不存在则返回null
     */
    public GameRoom getRoomById(String roomId) {
        String roomKey = ROOM_KEY_PREFIX + roomId;
        return (GameRoom) objectRedisTemplate.opsForValue().get(roomKey);
    }
    
    /**
     * 检查房间是否存在于ZSet中
     * 
     * @param roomId 房间ID
     * @return 房间的分数（创建时间戳），如果不存在返回null
     */
    public Double getRoomScore(String roomId) {
        return stringRedisTemplate.opsForZSet().score(ROOMS_ZSET_KEY, roomId);
    }
    
    /**
     * 获取房间总数
     * 
     * @return 房间总数
     */
    public long getRoomCount() {
        return stringRedisTemplate.opsForZSet().count(ROOMS_ZSET_KEY, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
    }

    // ==================== 游戏逻辑方法 ====================
    
    /**
     * 开始游戏
     * 
     * @param sessionId 创建者的会话ID
     * @param roomId 房间ID
     * @return 开始游戏结果
     */
    /**
     * 开始游戏
     * TODO: 练习二 - Redis缓存操作：读取和更新房间状态，完成步骤1和步骤4
     * 
     * 🎯 核心学习目标：Redis缓存管理
     * 1. 从Redis读取房间信息（objectRedisTemplate.opsForValue().get()）-自行完成
     * 2. 验证房间状态和权限（已经完成）
     * 3. 更新房间状态和玩家信息（已经完成）
     * 4. 将更新后的数据写回Redis（objectRedisTemplate.opsForValue().set()）-自行完成
     * 
     * 📊 Redis Key 使用：
     * - room:{roomId} -> GameRoom对象（JSON序列化）
     * - 需要读取房间信息，更新状态，然后保存回Redis
     * 
     * @param sessionId 会话ID
     * @param roomId 房间ID
     * @return 游戏房间信息
     */
    public Result<GameRoom> startGame(String sessionId, String roomId) {

        GameRoom room =null;//这里的room应该从redis中读取
        
         // 步骤1：需要从Redis读取房间 room 的信息

        
         // 步骤2：验证权限和状态（业务逻辑）
         if (room == null) {
             return Result.failure("房间不存在");
         }
         if (!room.getCreatorSessionId().equals(sessionId)) {
             return Result.failure("只有房间创建者才能开始游戏");
         }
         if (room.getStatus() != GameStatus.WAITING) {
             return Result.failure("游戏状态不正确，无法开始游戏");
         }
         if (room.getPlayers().size() < 2) {
             return Result.failure("至少需要2个玩家才能开始游戏");
         }
        
         // 步骤3：更新房间状态和玩家信息（内存操作）
         room.setTargetNumber(generateTargetNumber());
         room.setStatus(GameStatus.PLAYING);
         for (Player player : room.getPlayers().values()) {
             player.setHasGuessed(false);
             player.setGuess(null);
             player.setGuessResult(null);
         }
        
        // 步骤4：将更新后的房间信息保存到Redis（关键步骤）


        return Result.success(room);
    }

    /**
     * 停止游戏
     * 
     * @param sessionId 创建者的会话ID
     * @param roomId 房间ID
     * @return 停止游戏结果
     */
    /**
     * 停止游戏
     * TODO: 练习二 - Redis缓存操作：读取和更新房间状态
     * 
     * 🎯 核心学习目标：Redis缓存管理
     * 1. 从Redis读取房间信息（objectRedisTemplate.opsForValue().get()）-自行完成
     * 2. 验证房间状态和权限-自行完成
     * 3. 更新房间状态和玩家信息-自行完成
     * 4. 将更新后的数据写回Redis（objectRedisTemplate.opsForValue().set()）-自行完成
     * 
     * 📊 Redis Key 使用：
     * - room:{roomId} -> GameRoom对象（JSON序列化）
     * - 需要读取房间信息，更新状态，然后保存回Redis
     * 
     * @param sessionId 创建者的会话ID
     * @param roomId 房间ID
     * @return 停止游戏结果
     */
    public Result<GameRoom> stopGame(String sessionId, String roomId) {

        GameRoom room =null;//这里的room应该从redis中读取
        // 步骤1：从Redis读取房间信息

        
        // 步骤2：验证权限和状态（业务逻辑）

        
        // 步骤3：更新房间状态和玩家信息（内存操作）

        
        // 步骤4：将更新后的房间信息保存到Redis（关键步骤）
        

        return Result.success(room);

    }

    /**
     * 玩家猜测数字
     * 
     * @param sessionId 玩家会话ID
     * @param roomId 房间ID
     * @param guess 猜测的数字
     * @return 猜测结果
     */
    /**
     * 玩家猜测数字
     * TODO: 练习三 - Redis缓存操作：复杂的读取、更新和保存操作
     * 
     * 🎯 核心学习目标：Redis缓存管理的高级应用
     * 1. 从Redis读取房间信息（objectRedisTemplate.opsForValue().get()）
     * 2. 验证游戏状态和玩家权限
     * 3. 更新玩家猜测信息和游戏状态
     * 4. 将更新后的数据写回Redis（objectRedisTemplate.opsForValue().set()）
     * 5. 构建并返回DTO对象
     * 
     * 📊 Redis Key 使用：
     * - room:{roomId} -> GameRoom对象（JSON序列化）
     * - 需要读取房间信息，更新玩家状态，然后保存回Redis
     * 
     * 🔥 重点：这是最复杂的Redis操作，涉及多层数据更新
     * 
     * @param sessionId 玩家会话ID
     * @param roomId 房间ID
     * @param guess 猜测的数字
     * @return 猜测结果
     */
    public Result<GuessResultDto> makeGuess(String sessionId, String roomId, Integer guess) {
        GuessResultDto resultData = null;
        
        // 步骤1：从Redis读取房间信息


        // 步骤2：验证游戏状态

        
        // 步骤3：验证玩家权限和状态

        
        // 步骤4：更新玩家猜测信息（内存操作）

        
        // 步骤5：判断猜测结果并更新玩家状态

        
        // 步骤6：将更新后的房间信息保存到Redis（关键步骤）

        
        // 步骤7：构建并返回DTO对象

        return Result.success(resultData);

    }

    // ==================== 基础工具方法 ====================
    
    /**
     * 创建玩家对象
     * 
     * @param name 玩家名称
     * @param sessionId 会话ID
     * @return 玩家对象
     */
    private Player createPlayer(String name, String sessionId) {
        Player player = new Player();
        player.setName(name);
        player.setSessionId(sessionId);
        return player;
    }

    /**
     * 生成目标数字（1-100）
     * 
     * @return 1-100之间的随机数
     */
    private Integer generateTargetNumber() {
        return new Random().nextInt(100) + 1;
    }

    /**
     * 生成房间ID
     * 格式：room_时间戳_随机数
     * 
     * @return 唯一的房间ID
     */
    private String generateRoomId() {
        return "room_" + System.currentTimeMillis() + "_" + (int)(Math.random() * 1000);
    }
    
    /**
     * 🧹 清除所有Redis缓存（启动时调用）
     * 
     * 功能说明：
     * - 清除所有游戏相关的Redis数据
     * - 确保每次启动都是干净的状态
     * - 避免历史数据干扰新游戏
     * 
     * 清除内容：
     * - 所有房间数据：room:{roomId}
     * - 所有玩家数据：player:{sessionId}
     * - 所有玩家房间映射：player_room:{sessionId}
     * - 玩家名称集合：player_names
     * - 房间时间排序集合：rooms_by_time
     * 
     * 使用场景：
     * - 应用启动时自动调用（ApplicationReadyEvent）
     * - 手动清理缓存（管理接口）
     * - 测试环境数据重置
     * 
     * @return 清除结果，包含清理的详细信息
     */
    public Result<String> clearAllCache() {
        try {
            // 1. 清除所有房间数据
            Set<String> roomKeys = objectRedisTemplate.keys(ROOM_KEY_PREFIX + "*");
            if (roomKeys != null && !roomKeys.isEmpty()) {
                objectRedisTemplate.delete(roomKeys);
                log.info("已清除 {} 个房间数据", roomKeys.size());
            }
            
            // 2. 清除所有玩家数据
            Set<String> playerKeys = objectRedisTemplate.keys(PLAYER_KEY_PREFIX + "*");
            if (playerKeys != null && !playerKeys.isEmpty()) {
                objectRedisTemplate.delete(playerKeys);
                log.info("已清除 {} 个玩家数据", playerKeys.size());
            }
            
            // 3. 清除所有玩家房间映射
            Set<String> playerRoomKeys = stringRedisTemplate.keys(PLAYER_ROOM_KEY_PREFIX + "*");
            if (playerRoomKeys != null && !playerRoomKeys.isEmpty()) {
                stringRedisTemplate.delete(playerRoomKeys);
                log.info("已清除 {} 个玩家房间映射", playerRoomKeys.size());
            }
            
            // 4. 清除玩家名Set
            stringRedisTemplate.delete(PLAYER_NAMES_SET_KEY);
            log.info("已清除玩家名Set");
            
            // 5. 清除房间ZSet
            stringRedisTemplate.delete(ROOMS_ZSET_KEY);
            log.info("已清除房间ZSet");
            
            log.info("所有Redis缓存已清除完成");
            return Result.success("所有缓存已清除");
            
        } catch (Exception e) {
            log.error("清除Redis缓存时发生异常: {}", e.getMessage(), e);
            return Result.failure("清除缓存失败: " + e.getMessage());
        }
    }
}